﻿using System;
using System.Windows.Controls;
using System.Windows;
using System.Collections.Generic;
using System.Diagnostics;

namespace WickedFlame.GenDock
{
    public enum AnchorType { None, ButtonAnchor, CollapsibleAnchor };

    [TemplatePart(Name = "PART_RightContentHost", Type = typeof(StackPanel))]
    public class DockingLayoutManager : ContentControl
    {
        static DockingLayoutManager()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(DockingLayoutManager), new FrameworkPropertyMetadata(typeof(DockingLayoutManager)));
        }

        public DockingLayoutManager()
        {
            this.Loaded += new RoutedEventHandler(OnLoaded);
            this.SizeChanged += new SizeChangedEventHandler(OnSizeChanged);

            dockableContentList = new List<ContentDocument>();
        }
        
        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            //register events
            try
            {
                Window.GetWindow(this).LocationChanged += new EventHandler(OnWindowLocationChanged);
            }
            catch (NullReferenceException) { }
        }

        private void OnWindowLocationChanged(object sender, EventArgs e)
        {
            if (leftAnchor != null && leftAnchor is IDockableWindowPresenter)
                ((IDockableWindowPresenter)leftAnchor).RepositionDockedWindow();

            if (rightAnchor != null && rightAnchor is IDockableWindowPresenter)
                ((IDockableWindowPresenter)rightAnchor).RepositionDockedWindow();
        }

        private void OnSizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (leftAnchor != null && leftAnchor is IDockableWindowPresenter)
                ((IDockableWindowPresenter)leftAnchor).RepositionDockedWindow();

            if (rightAnchor != null && rightAnchor is IDockableWindowPresenter)
                ((IDockableWindowPresenter)rightAnchor).RepositionDockedWindow();
        }

        List<ContentDocument> dockableContentList;
        public void AddDockableContent(ContentDocument content)
        {
            dockableContentList.Add(content);
            content.RegisterManagerService(Service);

            InvalidateContent();
        }

        public void InvalidateContent()
        {
            if (leftAnchor != null)
            {
                leftAnchor.ClearContent();
                foreach (ContentDocument content in dockableContentList)
                {
                    if (content.AnchorPlace == LeftAnchorType)
                        leftAnchor.AddContent(content);
                }

                leftAnchor.OnApplyTemplate();
            }

            if (rightAnchor != null)
            {
                if (RightAnchorType == LeftAnchorType)
                    throw new Exception("LeftAnchorType and RightAnchorType of the DockingLayoutManager are the same.Pleache change one of the DockingTypes!");

                rightAnchor.ClearContent();
                foreach (ContentDocument content in dockableContentList) 
                {
                    if (content.AnchorPlace == RightAnchorType)
                        rightAnchor.AddContent(content);
                }

                rightAnchor.OnApplyTemplate();
            }

            
        }

        /// <summary>
        /// Gets executed by <see cref="DockeableContent"/> to hide itsself
        /// </summary>
        /// <param name="content"></param>
        public void Hide(ContentDocument content)
        {
            throw new NotImplementedException();
        }

        public void ShowContent(Type type)
        {
            // if content is in the left anchor
            bool set = leftAnchor.ShowContent(type);

            // if content is in the right anchor
            if (!set)
                set = rightAnchor.ShowContent(type);

            // if content is in a window
            if (!set)
            {
                Window wnd = Window.GetWindow(this);
                foreach (Window w in wnd.OwnedWindows)
                {
                    if (w is DockableWindow)
                    {
                        set = (w as DockableWindow).ShowContent(type);
                        if (set)
                            break;
                    }
                }
            }

            //reset content to anchor
            if (!set)
            {
                foreach (ContentDocument content in dockableContentList)
                {
                    Type t = content.GetType();
                    if (t == type)
                        if (content.AnchorPlace == LeftAnchorType)
                        {
                            leftAnchor.AddContent(content);
                            set = leftAnchor.ShowContent(content);
                        }
                        else
                        {
                            rightAnchor.AddContent(content);
                            set = rightAnchor.ShowContent(content);
                        }
                }
            }
        }

        public void ShowContent(ContentDocument document)
        {
            // if content is in the left anchor
            bool set = leftAnchor.ShowContent(document);

            // if content is in the right anchor
            if (!set)
                set = rightAnchor.ShowContent(document);

            // if content is in a window
            if (!set)
            {
                Window wnd = Window.GetWindow(this);
                foreach (Window w in wnd.OwnedWindows)
                {
                    if (w is DockableWindow)
                    {
                        set = (w as DockableWindow).ShowContent(document);
                        if (set)
                            break;
                    }
                }
            }

            //reset content to anchor
            if (!set)
            {
                foreach (ContentDocument content in dockableContentList)
                {
                    if (content == document)
                        if (content.AnchorPlace == LeftAnchorType)
                        {
                            leftAnchor.AddContent(content);
                            set = leftAnchor.ShowContent(content);
                        }
                        else
                        {
                            rightAnchor.AddContent(content);
                            set = leftAnchor.ShowContent(content);
                        }
                }
            }
        }

        DockingManagerService _service;
        internal DockingManagerService Service
        {
            get
            {
                if (_service == null)
                    _service = new DockingManagerService(this);
                return _service;
            }
        }

        public AnchorType LeftAnchorType
        {
            get { return (AnchorType)GetValue(LeftAnchorProperty); }
            set { SetValue(LeftAnchorProperty, value); }
        }

        public static readonly DependencyProperty LeftAnchorProperty =
            DependencyProperty.Register("LeftAnchorType", typeof(AnchorType), typeof(DockingLayoutManager));//, new PropertyMetadata(AnchorType.None));

        public AnchorType RightAnchorType
        {
            get { return (AnchorType)GetValue(RightAnchorProperty); }
            set
            {
                SetValue(RightAnchorProperty, value);
            }
        }

        public static readonly DependencyProperty RightAnchorProperty =
            DependencyProperty.Register("RightAnchorType", typeof(AnchorType), typeof(DockingLayoutManager));


        Anchor rightAnchor;
        internal Anchor RightAnchor
        {
            get
            {
                return rightAnchor;
            }
        }
        Anchor leftAnchor;
        internal Anchor LeftAnchor
        {
            get
            {
                return leftAnchor;
            }
        }

        internal Rect RightAnchorRectangle
        {
            get
            {
                var panel = GetTemplateChild("PART_RightAnchorTabPanel") as Panel;
                if (panel != null && leftAnchor != null)
                {
                    System.Windows.Media.GeneralTransform transform = panel.TransformToAncestor(Window.GetWindow(this.Parent));
                    Point rootPoint = transform.Transform(new Point(0, 0));
                    
                    return new Rect(rootPoint.X, rootPoint.Y, panel.RenderSize.Width, panel.RenderSize.Height);
                }
                return new Rect();
            }
        }
        internal Rect LeftAnchorRectangle
        {
            get
            {

                var panel = GetTemplateChild("PART_LeftAnchorTabPanel") as Panel;
                if (panel != null && leftAnchor != null)
                {
                    System.Windows.Media.GeneralTransform transform = panel.TransformToAncestor(Window.GetWindow(this));//this);
                    Point rootPoint = transform.Transform(new Point(0, 0));
                    
                    return new Rect(rootPoint.X, rootPoint.Y, panel.RenderSize.Width, panel.RenderSize.Height);
                }
                return new Rect();
            }
        }

        /// <summary>
        /// Overriden to get a reference to underlying template elements
        /// </summary>
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            switch (LeftAnchorType)
            {
                case AnchorType.ButtonAnchor:
                    leftAnchor = new ButtonAnchor();
                    break;
                case AnchorType.CollapsibleAnchor:
                    leftAnchor = new CollapsibleAnchor();
                    break;
                case AnchorType.None:
                    break;
            }

            
            switch (RightAnchorType)
            {
                case AnchorType.ButtonAnchor:
                    rightAnchor = new ButtonAnchor();
                    break;
                case AnchorType.CollapsibleAnchor:
                    rightAnchor = new CollapsibleAnchor();
                    break;
                case AnchorType.None:
                    break;
            }

            var rightAnchorPanel = GetTemplateChild("PART_RightAnchorTabPanel") as Panel;
            if (rightAnchorPanel != null && rightAnchor != null)
                rightAnchorPanel.Children.Add(rightAnchor);

            var leftAnchorPanel = GetTemplateChild("PART_LeftAnchorTabPanel") as Panel;
            if (leftAnchorPanel != null && leftAnchor != null)
                leftAnchorPanel.Children.Add(leftAnchor);

            InvalidateContent();
        }

        protected override void OnVisualChildrenChanged(DependencyObject visualAdded, DependencyObject visualRemoved)
        {
            base.OnVisualChildrenChanged(visualAdded, visualRemoved);
        }

        /// <summary>
        /// Called to arrange the size and content of GenDock.DockingLayoutManager
        /// </summary>
        /// <param name="arrangeBounds"></param>
        /// <returns></returns>
        protected override Size ArrangeOverride(Size arrangeBounds)
        {
            return base.ArrangeOverride(arrangeBounds);
        }

        protected override Size MeasureOverride(Size constraint)
        {
            //CenterGrid.Width = this.ActualWidth;
            //CenterGrid.Height = this.ActualHeight;
            //Resize();
            return constraint;
            //return base.MeasureOverride(constraint);
        }

        protected override void OnDragEnter(DragEventArgs e)
        {
            base.OnDragEnter(e);
        }

        protected override void OnDrop(DragEventArgs e)
        {
            //Array a = (Array)e.Data.GetData(DataFormats.FileDrop);
            //if (a != null)
            //{
            //    //string test = a.GetValue(0).ToString();
            //    Debug.WriteLine("dockinglayoutmanager: " + a.GetValue(0).ToString());
            //}
            if (!e.Handled)
            {
                e.Handled = Service.OnDrop(e.Data.GetData("content") as ContentDocument, e.GetPosition(Window.GetWindow(this)));
                //e.Handled = true;
            }
            base.OnDrop(e);
        }


        //public IList<UIElement> RightContent
        //{
        //    get
        //    {
        //        return (IList<UIElement>)base.GetValue(RightContentProperty);
        //    }
        //    set
        //    {
        //        base.SetValue(RightContentPropertyKey, value);
        //    }
        //}
        //private static readonly DependencyPropertyKey RightContentPropertyKey = DependencyProperty.RegisterReadOnly("RightContent", typeof(IList<UIElement>), typeof(DockingLayoutManager), new FrameworkPropertyMetadata(null));
        //public static readonly DependencyProperty RightContentProperty = RightContentPropertyKey.DependencyProperty;
        ////private const string RightContentHostTemplateName = "PART_RightContentHost";
    }
}
